Skip to content

perf(emoji): optimize FindEmojiSubmatchIndex using slice-based Trie - #38573

Merged
silverwind merged 8 commits into
go-gitea:mainfrom
SudhanshuMatrix:perf-emoji-trie
Jul 23, 2026
Merged

perf(emoji): optimize FindEmojiSubmatchIndex using slice-based Trie#38573
silverwind merged 8 commits into
go-gitea:mainfrom
SudhanshuMatrix:perf-emoji-trie

Conversation

@SudhanshuMatrix

Copy link
Copy Markdown
Contributor

This pull request optimizes FindEmojiSubmatchIndex in Gitea's emoji package (modules/emoji/emoji.go) by replacing the strings.Replacer-based search with a slice-based trie and a constant-time starting-byte check (isStartingByte).

The new implementation avoids heap allocations during the search and reduces CPU overhead when rendering Markdown, particularly for plain text that does not contain emojis.

Verification

Verified with unit tests:

go test -count=1 ./modules/emoji/...

Benchmarks:

go test -bench=. -benchmem ./modules/emoji/...

Results

Benchmark Before After
BenchmarkFindEmojiSubmatchIndex 168.3 ns/op, 2 allocs/op 85.78 ns/op, 1 alloc/op
BenchmarkFindEmojiSubmatchIndexNoMatch 239.8 ns/op, 1 alloc/op 105.1 ns/op, 0 allocs/op

Benchmark Output

goos: linux
goarch: amd64
pkg: gitea.dev/modules/emoji
cpu: Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz

BenchmarkFindEmojiSubmatchIndex-4              13498539        85.78 ns/op      16 B/op   1 allocs/op
BenchmarkFindEmojiSubmatchIndexNoMatch-4       11220450       105.1 ns/op        0 B/op   0 allocs/op
BenchmarkFindEmojiSubmatchIndexOld-4            6569360       168.3 ns/op      48 B/op   2 allocs/op
BenchmarkFindEmojiSubmatchIndexOldNoMatch-4     5026116       239.8 ns/op      32 B/op   1 allocs/op

Optimize the unicode emoji search function by replacing a slow and hacky strings.Replacer workaround with a custom slice-based Trie and starting-byte fast path. This improves performance by ~2.3x and eliminates all memory allocations in the common 'no-match' path.

Signed-off-by: Sudhanshu Singh <sudhanshuwriterblc@gmail.com>
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Jul 22, 2026
Comment thread modules/emoji/emoji.go Outdated
SudhanshuMatrix and others added 2 commits July 22, 2026 17:01
Relocate the custom slice-based Trie structure and tests from modules/emoji to modules/util as a generic utility

Signed-off-by: Sudhanshu Singh <sudhanshuwriterblc@gmail.com>
Only TrieNode/Insert/Match are used externally, so unexport trieEdge and
the node fields. Extract the duplicated child-lookup loop into a child()
helper, and add a keycap-emoji test covering the ASCII start-byte path.

Assisted-by: Claude Code:claude-opus-4-8

@silverwind silverwind left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did some cleanups in 00e37e1.

@GiteaBot GiteaBot added lgtm/need 1 This PR needs approval from one additional maintainer to be merged. and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Jul 22, 2026
@GiteaBot GiteaBot added lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. and removed lgtm/need 1 This PR needs approval from one additional maintainer to be merged. labels Jul 22, 2026
@wxiaoguang

wxiaoguang commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

did some cleanups in 00e37e1.

removed the useless and unclear test "a \U00000030\U0000fe0f\U000020e3 b".
\U00000030 is ASCII digit 0. Such case is already covered by many other cases.


OK, added it back and added more comments to explain the "keycap emoji" problem

@wxiaoguang
wxiaoguang force-pushed the perf-emoji-trie branch 2 times, most recently from 5b35763 to be6bfe2 Compare July 23, 2026 07:31
@silverwind
silverwind enabled auto-merge (squash) July 23, 2026 08:00
@silverwind silverwind added the reviewed/wait-merge This pull request is part of the merge queue. It will be merged soon. label Jul 23, 2026
@silverwind
silverwind merged commit ee10ae1 into go-gitea:main Jul 23, 2026
23 checks passed
@GiteaBot GiteaBot added this to the 28.0.0 milestone Jul 23, 2026
@GiteaBot GiteaBot removed the reviewed/wait-merge This pull request is part of the merge queue. It will be merged soon. label Jul 23, 2026
silverwind added a commit to bircni/gitea that referenced this pull request Jul 24, 2026
* origin/main: (21 commits)
  feat(setting): add shared [redis] section as default for redis-backed subsystems (go-gitea#38550)
  fix(webhook): remove slack channel name check (go-gitea#38608)
  ci: derive topic labels from PR title (go-gitea#38595)
  fix: download dropdown menu clipped on the branches page (go-gitea#38604)
  enhance(actions): action view enhancements (go-gitea#38594)
  enhance: keep status check list scrolled on merge box reload (go-gitea#38597)
  fix: make auth source group sync correctly handle team removal (go-gitea#37161)
  fix(oauth2): enforce mandatory 2FA policy on OAuth2 authorize/grant endpoints (go-gitea#38591)
  refactor: hide git repo path details from more packages (go-gitea#38601)
  fix(project): prevent database mutations on invalid MoveIssues payload (go-gitea#38600)
  refactor: retry file remove/rename when a file is busy and clean up os detection (go-gitea#38588)
  fix(actions): make SingleWorkflow.Marshal round-trip multi-line run blocks (stop silent job stranding) (go-gitea#38520)
  fix(issue): display error toast on batch action failures instead of reloading page (go-gitea#38593)
  perf(emoji): optimize FindEmojiSubmatchIndex using slice-based Trie (go-gitea#38573)
  test(e2e): add pull request merge box test, update AGENTS.md (go-gitea#38576)
  fix(api): align Swagger schemas for UserSettings and TopicListResponse (go-gitea#38590)
  fix(file-tree): handle submodule links and missing view container (go-gitea#38033)
  refactor: clean up git repo and model migration packages (go-gitea#38564)
  [skip ci] Updated translations via Crowdin
  fix(actions): fail unexpandable reusable workflow callers and decouple the job emitter's cross-run processing (go-gitea#38565)
  ...

# Conflicts:
#	services/actions/reusable_workflow_test.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants